package com.ax.framework.jfinal.server

import cn.hutool.core.util.ReflectUtil
import cn.hutool.log.LogFactory
import com.jfinal.aop.Invocation
import com.jfinal.core.*
import com.jfinal.render.Render
import com.jfinal.render.RenderException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class AppActionHandler : ActionHandler() {

    val log = LogFactory.get()

    override fun handle(target: String, request: HttpServletRequest, response: HttpServletResponse, isHandled: BooleanArray) {

        if(request.method=="OPTIONS"){
            renderManager.renderFactory.nullRender.setContext(request, response).render()
            return
        }

        /*
		if (target.indexOf('.') != -1) {
			return ;
		}*/

        isHandled[0] = true
        val urlPara = arrayOf<String?>(null)
        val action = actionMapping.getAction(target, urlPara)

        if (action == null) {
            if (log.isWarnEnabled) {
                val qs = request.queryString
                log.warn("404 Action Not Found: " + if (qs == null) target else "$target?$qs")
            }
            renderManager.renderFactory.getErrorRender(404).setContext(request, response).render()
            return
        }

        var controller: Controller? = null
        try {
            // Controller controller = action.getControllerClass().newInstance();
            controller = controllerFactory.getController(action.controllerClass)
            if (injectDependency) {
                com.jfinal.aop.Aop.inject(controller)
            }
            val _init_ = ReflectUtil.getMethod(controller!!::class.java, "_init_", action::class.java, request::class.java, response::class.java, String::class.java)
            _init_.isAccessible = true
            _init_.invoke(controller, action, request, response, urlPara[0])


            if (devMode) {
                if (ActionReporter.isReportAfterInvocation(request)) {
                    Invocation(action, controller).invoke()
                    ActionReporter.report(target, controller, action)
                } else {
                    ActionReporter.report(target, controller, action)
                    Invocation(action, controller).invoke()
                }
            } else {
                Invocation(action, controller).invoke()
            }

            var render: Render? = controller.render
            if (render is ForwardActionRender) {
                val actionUrl = render.actionUrl
                if (target == actionUrl) {
                    throw RuntimeException("The forward action url is the same as before.")
                } else {
                    handle(actionUrl, request, response, isHandled)
                }
                return
            }

            if (render == null) {
                render = renderManager.renderFactory.getDefaultRender(action.viewPath + action.methodName)
            }
            render!!.setContext(request, response, action.viewPath).render()
        } catch (e: RenderException) {
            if (log.isErrorEnabled) {
                val qs = request.queryString
                log.error(if (qs == null) target else "$target?$qs", e)
            }
        } catch (e: ActionException) {
            handleActionException(target, request, response, action, e)
        } catch (e: Exception) {
            //
            markdownAppErrorResolver(request, response, action, e)
        } finally {
            val _clear_ = ReflectUtil.getMethod(controller!!::class.java, "_clear_")
            _clear_.isAccessible = true
            _clear_.invoke(controller)
        }
    }


    private fun handleActionException(target: String, request: HttpServletRequest?, response: HttpServletResponse, action: Action, e: ActionException) {
        val errorCode = e.errorCode
        var msg: String? = null
        if (errorCode == 404) {
            msg = "404 Not Found: "
        } else if (errorCode == 400) {
            msg = "400 Bad Request: "
        } else if (errorCode == 401) {
            msg = "401 Unauthorized: "
        } else if (errorCode == 403) {
            msg = "403 Forbidden: "
        }

        if (msg != null) {
            if (log.isWarnEnabled) {
                val qs = request!!.queryString
                msg = msg + if (qs == null) target else "$target?$qs"
                if (e.message != null) {
                    msg = msg + "\n" + e.message
                }
                log.warn(msg)
            }
        } else {
            if (log.isErrorEnabled) {
                val qs = request!!.queryString
                log.error(errorCode.toString() + " Error: " + if (qs == null) target else "$target?$qs", e)
            }
        }

        e.errorRender.setContext(request, response, action.viewPath).render()
    }
}